﻿using System;
using System.Collections.Generic;

namespace Furesoft.Papi.AST
{
    public abstract class INode : IObservable<INode>, IDisposable
    {
        private List<IObserver<INode>> observers;

        public INode()
        {
            observers = new List<IObserver<INode>>();
        }

        public void Dispose()
        {
            EndTransmission();
        }

        protected void Propchanged(INode loc)
        {
            foreach (var observer in observers)
            {
                try {
                    observer.OnNext(loc);
                }
                catch (Exception ex) {
                    observer.OnError(ex);
                }                    
            }
        }

        protected void EndTransmission()
        {
            foreach (var observer in observers.ToArray())
                if (observers.Contains(observer))
                    observer.OnCompleted();

            observers.Clear();
        }

        public IDisposable Subscribe(IObserver<INode> observer)
        {
            if (!observers.Contains(observer))
                observers.Add(observer);
            return new Unsubscriber(observers, observer);
        }

        public void Accept(INodeVisitor v)
        {
            v.Visit(this);
        }

        private class Unsubscriber : IDisposable
        {
            private List<IObserver<INode>> _observers;
            private IObserver<INode> _observer;

            public Unsubscriber(List<IObserver<INode>> observers, IObserver<INode> observer)
            {
                this._observers = observers;
                this._observer = observer;
            }

            public void Dispose()
            {
                if (_observer != null && _observers.Contains(_observer))
                    _observers.Remove(_observer);
            }
        }
    }
}